package utils

import (
	"fmt"
	"openwechat/logs"
	"strconv"
	"strings"

	jsoniter "github.com/json-iterator/go"
	"github.com/thedevsaddam/gojsonq/v2"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type JsonQ struct {
	jq *gojsonq.JSONQ
}

// QueryParam .
type QueryParam struct {
	In     map[string]interface{}
	Query  map[string]interface{}
	Order  map[string]string
	Like   string
	Limit  int
	Offset int
}

// source []interface{}, map[string]interface{}, map[string][]interface{}
func NewJsonQ(source interface{}) (*JsonQ, error) {
	marshal, err := json.Marshal(source)
	if err != nil {
		return nil, fmt.Errorf("JsonQ:%s", err.Error())
	}
	return &JsonQ{jq: gojsonq.New().FromString(string(marshal))}, nil
}

func (j *JsonQ) Result() interface{} {
	return j.jq.Get()
}

func (j *JsonQ) GroupBy(filed string) *JsonQ {
	j.jq.GroupBy(filed)
	return j
}

func (j *JsonQ) Select(properties ...string) *JsonQ {
	j.jq.Select(properties...)
	return j
}

func (j *JsonQ) FindAndCount(bean interface{}) (int, error) {
	count, err := j.Count()
	if err != nil {
		return 0, err
	}
	return count, j.Find(bean)
}

func (j *JsonQ) Find(bean interface{}) error {
	j.jq.Out(bean)
	return j.jq.Error()
}

func (j *JsonQ) QueryParam(queryParam *QueryParam, likeFields ...string) *JsonQ {
	if queryParam != nil {
		j.Offset(queryParam.Offset).Limit(queryParam.Limit)
		for k, v := range queryParam.Query {
			j.Query(k, v)
		}
		j.Like(queryParam.Like, likeFields...)
		j.In(queryParam.In)
		j.Order(queryParam.Order)
	}
	return j
}

func (j *JsonQ) Query(filed string, val interface{}) *JsonQ {
	if val == "" || val == nil {
		return j
	}
	j.jq.WhereEqual(filed, val)
	return j
}

func (j *JsonQ) Clone() *JsonQ {
	newJQ := new(gojsonq.JSONQ)
	*newJQ = *j.jq
	return &JsonQ{jq: newJQ}
}

func (j *JsonQ) Where(field, operator string, val interface{}) *JsonQ {
	j.jq.Where(field, operator, val)
	return j
}
func (j *JsonQ) WhereEq(field string, val interface{}) *JsonQ {
	j.jq.WhereEqual(field, val)
	return j
}

func (j *JsonQ) In(in map[string]interface{}) *JsonQ {
	for k, v := range in {
		if query, ok := v.(string); ok {
			split := strings.Split(query, ",")
			ins := make([]int, 0)
			fls := make([]float64, 0)
			for _, sp := range split {
				i, err := strconv.Atoi(sp)
				if err != nil {
					logs.Error(err.Error())
				}
				ins = append(ins, i)
				fl, err := strconv.ParseFloat(sp, 64)
				if err != nil {
					logs.Error(err.Error())
				}
				fls = append(fls, fl)
			}
			j.jq.Where(k, "in", split)
			j.jq.OrWhere(k, "in", ins)
			j.jq.OrWhere(k, "in", fls)
		}
	}
	return j
}

func (j *JsonQ) Like(like string, likeFields ...string) *JsonQ {
	if like != "" {
		for _, otherField := range likeFields {
			j.jq.OrWhere(otherField, "contains", like)
		}
	}
	return j
}

//func (j *JsonQ) clearPage() *JsonQ {
//	j.jq.Limit(0)
//	j.jq.Offset(0)
//	return j
//}

func (j *JsonQ) Limit(limit int) *JsonQ {
	if limit == -1 {
		limit = 0
	}
	j.jq.Limit(limit)
	return j
}

func (j *JsonQ) Offset(offset int) *JsonQ {
	j.jq.Offset(offset)
	return j
}

func (j *JsonQ) Count() (count int, err error) {
	// 分页数据数量
	count = j.jq.Count()
	if j.jq.Error() != nil {
		return 0, j.jq.Error()
	}
	return count, nil
}

func (j *JsonQ) Order(sort map[string]string) *JsonQ {
	for k, v := range sort {
		j.jq.SortBy(k, v)
	}
	return j
}

func BeanMarshal(body, bean interface{}) error {
	marshal, err := json.Marshal(body)
	if err != nil {
		return err
	}
	return json.Unmarshal(marshal, bean)
}
